package com.demo.util;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 高并发6位唯一字符串生成器
 * 格式：[1位前缀][5位数字字母组合]
 * 特性：大小写不敏感的唯一性检查，生成结果包含大小写
 */
public class ConcurrentShortCodeGenerator {
    private static final String CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    private static final int BASE = CHARACTERS.length();
    /**
     * 随机部分长度
     */
    private static final int CODE_LENGTH = 5;
    /**
     * 最大重试次数
     */
    private static final int MAX_RETRY = 1000;

    /**
     * 用于唯一性检查的集合（存储大写形式）
     */
    private final Set<String> generatedCodes;
    /**
     * 原子序列号，用于高并发下的序列生成
     */
    private final AtomicLong sequenceCounter;

    public ConcurrentShortCodeGenerator() {
        this.generatedCodes = Collections.newSetFromMap(new ConcurrentHashMap<>());
        this.sequenceCounter = new AtomicLong(System.currentTimeMillis());
    }
    /**
     * 生成6位唯一字符串（1位前缀 + 5位随机）
     * @param prefix 前缀字符，如 "M"
     * @return 6位唯一字符串
     */
    public String generate(String prefix) {
        if (prefix == null || prefix.length() != 1) {
            throw new IllegalArgumentException("前缀必须为单个字符");
        }
        int retryCount = 0;
        while (retryCount < MAX_RETRY) {
            String randomPart = generateRandomPart();
            String fullCode = prefix + randomPart;
            String normalizedCode = normalizeCase(fullCode);
            // CAS方式检查唯一性
            if (generatedCodes.add(normalizedCode)) {
                return fullCode;
            }
            retryCount++;
            // 每100次重试短暂等待，避免CPU空转
            if (retryCount % 100 == 0) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }
        // 重试失败，使用序列生成保证唯一性
        return generateSequentialCode(prefix);
    }

    /**
     * 生成5位随机字符串（包含数字和大小写字母）
     */
    private String generateRandomPart() {
        StringBuilder sb = new StringBuilder(CODE_LENGTH);
        ThreadLocalRandom random = ThreadLocalRandom.current();

        for (int i = 0; i < CODE_LENGTH; i++) {
            int index = random.nextInt(BASE);
            sb.append(CHARACTERS.charAt(index));
        }

        return sb.toString();
    }

    /**
     * 序列生成策略（保证唯一性的后备方案）
     */
    private String generateSequentialCode(String prefix) {
        long sequence = sequenceCounter.getAndIncrement();
        String sequentialPart = convertToMixedCaseBase62(sequence);
        String fullCode = prefix + sequentialPart;
        String normalizedCode = normalizeCase(fullCode);
        generatedCodes.add(normalizedCode);
        return fullCode;
    }

    /**
     * 将序列号转换为5位base62字符串，并随机大小写
     */
    private String convertToMixedCaseBase62(long number) {
        StringBuilder sb = new StringBuilder(CODE_LENGTH);
        long value = Math.abs(number);
        // 转换为base62数字（始终使用大写）
        for (int i = 0; i < CODE_LENGTH; i++) {
            // 只使用字母部分（26 * 2=52个字母）
            int index = (int) (value % 52);
            value /= 52;
            char baseChar = (char) (index < 26 ? 'A' + index :'a' + (index - 26));
            sb.append(baseChar);
        }

        // 反转并确保长度为5
        StringBuilder result = new StringBuilder(sb.reverse().toString());
        while (result.length() < CODE_LENGTH) {
            result.insert(0, "A"); // 补'A'
        }
        return result.toString();
    }

    /**
     * 标准化大小写（用于唯一性检查）
     */
    private String normalizeCase(String code) {
        // 统一转为大写进行唯一性比较
        return code.toUpperCase();
    }

    /**
     * 检查编码是否已存在
     */
    public boolean contains(String code) {
        return generatedCodes.contains(normalizeCase(code));
    }

    /**
     * 获取已生成编码数量
     */
    public int getGeneratedCount() {
        return generatedCodes.size();
    }

    /**
     * 清理生成的编码记录（防止内存溢出）
     */
    public void cleanup() {
        if (generatedCodes.size() > 100000) {
            generatedCodes.clear();
        }
    }

    public static void main(String[] args) throws Exception {
        System.out.println("=== 开始高并发6位唯一字符串生成测试 ===\n");
        // 测试配置
        int threadCount = 10;           // 并发线程数
        int generateCountPerThread = 2000000; // 每线程生成数量
        int totalExpected = threadCount * generateCountPerThread;

        // 创建生成器
        ConcurrentShortCodeGenerator generator = new ConcurrentShortCodeGenerator();

        // 用于收集结果的线程安全集合
        Set<String> allCodes = Collections.synchronizedSet(new HashSet<>());
        Map<String, AtomicInteger> duplicateCheck = new ConcurrentHashMap<>();
        List<String> generationOrder = Collections.synchronizedList(new ArrayList<>());

        // 创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(threadCount);
        CountDownLatch startLatch = new CountDownLatch(1);
        CountDownLatch endLatch = new CountDownLatch(threadCount);

        // 统计信息
        AtomicInteger totalGenerated = new AtomicInteger(0);
        AtomicInteger collisionCount = new AtomicInteger(0);

        long startTime = System.currentTimeMillis();

        // 提交任务
        for (int i = 0; i < threadCount; i++) {
            final int threadId = i;
            final String prefix = "M"; // 测试使用M前缀

            executor.submit(() -> {
                try {
                    startLatch.await(); // 等待同时开始

                    for (int j = 0; j < generateCountPerThread; j++) {
                        String code = generator.generate(prefix);
                        totalGenerated.incrementAndGet();

                        // 检查唯一性
                        if (!allCodes.add(code)) {
                            collisionCount.incrementAndGet();
                            System.err.printf("❌ 发现重复: %s (线程%d)%n", code, threadId);
                        }

                        // 记录生成顺序和计数
                        generationOrder.add(code);
                        duplicateCheck.computeIfAbsent(code, k -> new AtomicInteger(0)).incrementAndGet();

                        // 进度提示
                        if ((j + 1) % 50 == 0) {
                            System.out.printf("线程%d: 已生成 %d/%d%n", threadId, j + 1, generateCountPerThread);
                        }
                    }

                    System.out.printf("✅ 线程%d 完成任务%n", threadId);

                } catch (Exception e) {
                    System.err.printf("线程%d 异常: %s%n", threadId, e.getMessage());
                } finally {
                    endLatch.countDown();
                }
            });
        }

        // 开始测试
        System.out.println("启动所有线程...");
        startLatch.countDown();

        // 等待所有线程完成
        System.out.println("等待线程完成...");
        boolean completed = endLatch.await(2, TimeUnit.MINUTES);

        long endTime = System.currentTimeMillis();
        long duration = endTime - startTime;

        // 关闭线程池
        executor.shutdown();

        if (!completed) {
            System.err.println("⚠️  测试超时，可能还有线程在运行");
            executor.shutdownNow();
        }

        // 统计结果
        int actualTotal = totalGenerated.get();
        int uniqueCount = allCodes.size();
        int duplicates = collisionCount.get();

        System.out.println("\n" + "=".repeat(60));
        System.out.println("📊 测试结果统计");
        System.out.println("=".repeat(60));

        System.out.printf("并发线程数: %d%n", threadCount);
        System.out.printf("每线程生成数: %d%n", generateCountPerThread);
        System.out.printf("预期总数: %d%n", totalExpected);
        System.out.printf("实际生成总数: %d%n", actualTotal);
        System.out.printf("唯一编码数: %d%n", uniqueCount);
        System.out.printf("重复编码数: %d%n", duplicates);
        System.out.printf("测试耗时: %d ms%n", duration);
        System.out.printf("QPS: %.2f 个/秒%n", actualTotal * 1000.0 / duration);

        // 详细重复分析
        if (duplicates > 0) {
            System.out.println("\n🔍 重复编码详细分析:");
            duplicateCheck.entrySet().stream()
                    .filter(entry -> entry.getValue().get() > 1)
                    .forEach(entry -> {
                        System.out.printf("重复编码: %s, 重复次数: %d%n",
                                entry.getKey(), entry.getValue().get());
                    });
        }

        // 样本输出
        System.out.println("\n📝 生成的样本编码:");
        for (int i = 0; i < Math.min(10, generationOrder.size()); i++) {
            System.out.printf("样本%d: %s%n", i + 1, generationOrder.get(i));
        }

        // 字符分布统计
        System.out.println("\n🔤 字符类型分布统计:");
        analyzeCharacterDistribution(generationOrder);

        // 测试结论
        System.out.println("\n✅ 测试结论:");
        if (duplicates == 0) {
            System.out.println("🎉 测试通过！所有生成的编码都是唯一的。");
        } else {
            System.out.printf("❌ 测试失败！发现 %d 个重复编码。%n", duplicates);
        }

        System.out.println("生成的编码总数: " + generator.getGeneratedCount());
    }

    /**
     * 分析字符分布
     */
    private static void analyzeCharacterDistribution(List<String> codes) {
        Map<Character, Integer> charCount = new HashMap<>();
        int totalChars = 0;

        for (String code : codes) {
            for (char c : code.toCharArray()) {
                charCount.put(c, charCount.getOrDefault(c, 0) + 1);
                totalChars++;
            }
        }

        // 分类统计
        int digits = 0, upperCase = 0, lowerCase = 0;
        for (char c : charCount.keySet()) {
            if (Character.isDigit(c)) digits += charCount.get(c);
            else if (Character.isUpperCase(c)) upperCase += charCount.get(c);
            else if (Character.isLowerCase(c)) lowerCase += charCount.get(c);
        }

        System.out.printf("数字(0-9): %d (%.1f%%)%n", digits, digits * 100.0 / totalChars);
        System.out.printf("大写字母: %d (%.1f%%)%n", upperCase, upperCase * 100.0 / totalChars);
        System.out.printf("小写字母: %d (%.1f%%)%n", lowerCase, lowerCase * 100.0 / totalChars);
    }


}